package com.je.gateway.router.loader;

import com.je.gateway.router.model.paramValue.ConfigParamValues;
import com.je.gateway.router.model.paramValue.ConfigValues;
import com.je.gateway.xml.AbstractXmlConfigResourceLoader;
import com.je.gateway.xml.ConfigResourceLoader;
import org.dom4j.Element;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: jecloud-gateway
 * @author: LIULJ
 * @create: 2021/7/4
 * @description:
 */
public class ConfigParamValuesResourceLoader extends AbstractXmlConfigResourceLoader<Map<String,ConfigParamValues>> {

    private static final String DEFAULT_CONFIG_PAHT = "values.xml";
    private static final String PARAM_VALUES_NODE = "paramValues";
    private static final String DEFINE_VALUES_NODE = "values";
    private static final String DEFINE_VALUES_ATTRONITE_NAME = "name";
    private static final String DEFINE_VALUES_ATTRONITE_TYPE = "type";
    private static final String TABLE_ATTRIBUTE_PARAMNAME_KEY = "paramName";
    private static final String TABLE_ATTRIBUTE_REF_KEY = "microServiceName";
    private static final String DEFINE_VALUE_NODE = "value";

    /**
     * valueRef
     */
    protected static final String DEFINE_VALUEREF_KEY = "valueRef";

    protected volatile boolean loaded = false;

    public ConfigParamValuesResourceLoader() {
        this(DEFAULT_CONFIG_PAHT);
    }

    public ConfigParamValuesResourceLoader(String resourcePath) {
        super(resourcePath);
    }

    @Override
    public Map<String,ConfigParamValues> parse(Element rootElement) {
        Map<String,ConfigParamValues> maps = new HashMap<>();
        synchronized (ConfigParamValuesResourceLoader.class){
            Map<String,ConfigValues> configValuesMap = parseValues(rootElement);
            Map<String,ConfigValues> dynamicValuesMap = loadDynamicValues();
            if(dynamicValuesMap != null && !dynamicValuesMap.isEmpty()){
                for (Map.Entry<String,ConfigValues> eachDynamicConfigValue : dynamicValuesMap.entrySet()) {
                    if(!configValuesMap.containsKey(eachDynamicConfigValue.getKey())){
                        configValuesMap.put(eachDynamicConfigValue.getKey(),eachDynamicConfigValue.getValue());
                        continue;
                    }
                    configValuesMap.get(eachDynamicConfigValue.getKey()).addAllValue(eachDynamicConfigValue.getValue().getValues());
                }
            }
            maps = parseParamValues(rootElement,configValuesMap);
            loaded = true;
        }
        return maps;
    }

    private Map<String,ConfigValues> loadDynamicValues(){
        ConfigResourceLoader<Map<String,ConfigValues>> configResourceLoader = new DynamicConfigParamValuesResourceLoader();
        return configResourceLoader.load();
    }

    /**
     * 加载values
     * @param rootElement
     * @return
     */
    private Map<String,ConfigValues> parseValues(Element rootElement){
        Map<String, ConfigValues> configValuesMap = new HashMap<>();
        List<Element> defineValuesElements = rootElement.elements(DEFINE_VALUES_NODE);
        if(defineValuesElements == null || defineValuesElements.isEmpty()){
            return new HashMap<>();
        }
        ConfigValues configValues;
        for (Element eachValuesElement : defineValuesElements) {
            configValues = new ConfigValues();
            configValues.setName(eachValuesElement.attributeValue(DEFINE_VALUES_ATTRONITE_NAME));
            configValues.setType(eachValuesElement.attributeValue(DEFINE_VALUES_ATTRONITE_TYPE));
            List<Element> valueElements = eachValuesElement.elements();
            for (Element eachValueElement : valueElements) {
                configValues.addValue(eachValueElement.getStringValue());
            }
            configValuesMap.put(configValues.getName() + "_" + configValues.getType(),configValues);
        }
        return configValuesMap;
    }

    /**
     * 加载ParamValues
     * @param rootElement
     * @return
     */
    private Map<String,ConfigParamValues> parseParamValues(Element rootElement,Map<String,ConfigValues> configValuesMap){
        Map<String,ConfigParamValues> maps = new HashMap<>();
        List<Element> tableElements = rootElement.elements(PARAM_VALUES_NODE);
        if(tableElements == null || tableElements.isEmpty()){
            return new HashMap<>();
        }
        ConfigParamValues configParamValues;
        for (Element eachTableElement : tableElements) {
            configParamValues = new ConfigParamValues();
            configParamValues.setParamName(eachTableElement.attributeValue(TABLE_ATTRIBUTE_PARAMNAME_KEY));
            configParamValues.setMicroServiceName(eachTableElement.attributeValue(TABLE_ATTRIBUTE_REF_KEY));
            List<Element> valueElements = eachTableElement.elements(DEFINE_VALUE_NODE);
            if(valueElements != null && !valueElements.isEmpty()){
                for (Element eachValueElement : valueElements) {
                    configParamValues.addTable(eachValueElement.getStringValue());
                }
            }
            List<Element> valueRefElements = eachTableElement.elements(DEFINE_VALUEREF_KEY);
            for (Element eachValueRefElement : valueRefElements) {
                if(configValuesMap.containsKey(eachValueRefElement.attributeValue(DEFINE_VALUES_ATTRONITE_NAME) + "_" + eachValueRefElement.attributeValue(DEFINE_VALUES_ATTRONITE_TYPE))){
                    ConfigValues configValues = configValuesMap.get(eachValueRefElement.attributeValue(DEFINE_VALUES_ATTRONITE_NAME) + "_" + eachValueRefElement.attributeValue(DEFINE_VALUES_ATTRONITE_TYPE));
                    configParamValues.addAll(configValues.getValues());
                }
            }
            maps.put(configParamValues.getParamName() + "_" + configParamValues.getMicroServiceName(),configParamValues);
        }
        return maps;
    }

}
